#include <REG51.H>
#include <Display.h>
#include <LCD1602.h>
#include <Clock.h>
#include <Mode.h>
#include <Stopwatch.h>
#include <Timing.h>
#include <Buzzer.h>

#define TIMER1_TH1 0x3C // 定时器初值，每50ms中断一次
#define TIMER1_TL0 0xB0 // 65536-50000 = 0x3CB0

/**
 * @brief  LCD显示时钟功能初始化，注意，这跟LCD初始化不一样
 * @param  None
 * @retval None
 */
void Display_init(void)
{
    lcd_init(); // LCD初始化

    TMOD &= 0x0F;
    TMOD |= 0x10; // 方式1，定时器模式
    TH1 = TIMER1_TH1;
    TL1 = TIMER1_TL0;
    ET1 = 1;
    EA = 1;
    TR1 = 1;
}

/**
 * @brief  LCD在指定行显示日期与时间
 * @param  y1: 日期显示的y坐标
 * @param  y2: 时间显示的y坐标
 * @retval None
 */
static void Display_Clock(unsigned char y1, unsigned char y2)
{
    lcd_set_pos(3, y1);
    lcd_wstring("20");
    lcd_wchar(Clock_buff.year / 10 + '0');
    lcd_wchar(Clock_buff.year % 10 + '0');
    lcd_wchar('-');

    lcd_wchar(Clock_buff.month / 10 + '0');
    lcd_wchar(Clock_buff.month % 10 + '0');
    lcd_wchar('-');

    lcd_wchar(Clock_buff.day / 10 + '0');
    lcd_wchar(Clock_buff.day % 10 + '0');

    lcd_set_pos(4, y2);
    lcd_wchar(Clock_buff.hour / 10 + '0');
    lcd_wchar(Clock_buff.hour % 10 + '0');
    lcd_wchar(':');

    lcd_wchar(Clock_buff.minute / 10 + '0');
    lcd_wchar(Clock_buff.minute % 10 + '0');
    if (System_Mode == Mode_Clock || System_Mode == Mode_hour_report)
        Clock_Tick ? lcd_wchar('\0') : lcd_wchar(':');
    else
        lcd_wchar(':');

    lcd_wchar(Clock_buff.second / 10 + '0');
    lcd_wchar(Clock_buff.second % 10 + '0');
}

/**
 * @brief  LCD显示菜单
 * @param  None
 * @retval None
 */
static void Display_menu(void)
{
    Display_Clock(0, 1);

    lcd_set_pos(1, 2);
    lcd_wstring("Clock timing");
    lcd_set_pos(1, 3);
    lcd_wstring("Stopwatch");
    if (Menu_option == 0)
    {
        lcd_set_pos(0, 2);
        lcd_wchar('>');
        lcd_set_pos(0, 3);
        lcd_wchar('\0');
    }
    else
    {
        lcd_set_pos(0, 2);
        lcd_wchar('\0');
        lcd_set_pos(0, 3);
        lcd_wchar('>');
    }
}

/**
 * @brief  LCD显示秒表，显示格式 00:00:00:00
 * @param  None
 * @retval None
 */
static void Display_Stopwatch(void)
{
    // 显示秒表状态
    lcd_set_pos(4, 0);
    switch (Stopwatch_buff.status)
    {
    case Stopwatch_status_start:
        lcd_wstring(" start ");
        break;

    case Stopwatch_status_suspend:
        lcd_wstring("suspend");
        break;

    case Stopwatch_status_stop:
        lcd_wstring(" stop  ");
        break;
    }

    // 显示秒表计时时间
    lcd_set_pos(2, 2);
    lcd_wchar(Stopwatch_buff.hour / 10 + '0');
    lcd_wchar(Stopwatch_buff.hour % 10 + '0');
    lcd_wchar(':');
    lcd_wchar(Stopwatch_buff.minute / 10 + '0');
    lcd_wchar(Stopwatch_buff.minute % 10 + '0');
    lcd_wchar(':');
    lcd_wchar(Stopwatch_buff.second / 10 + '0');
    lcd_wchar(Stopwatch_buff.second % 10 + '0');
    lcd_wchar(':');
    lcd_wchar(Stopwatch_buff.millisecond / 10 + '0');
    lcd_wchar(Stopwatch_buff.millisecond % 10 + '0');
}

/**
 * @brief  LCD显示调时
 * @param  None
 * @retval None
 */
static void Display_Timing(void)
{
    if (Clock_Tick)
    {
        switch (Timing_buff)
        {
        case Timing_pos_year:
            lcd_set_pos(3, 1);
            lcd_wstring("    ");
            break;

        case Timing_pos_month:
            lcd_set_pos(8, 1);
            lcd_wstring("  ");
            break;

        case Timing_pos_day:
            lcd_set_pos(11, 1);
            lcd_wstring("  ");
            break;

        case Timing_pos_hour:
            lcd_set_pos(4, 2);
            lcd_wstring("  ");
            break;

        case Timing_pos_minute:
            lcd_set_pos(7, 2);
            lcd_wstring("  ");
            break;

        case Timing_pos_second:
            lcd_set_pos(10, 2);
            lcd_wstring("  ");
            break;
        }
    }
}

/**
 * @brief  驱动LCD显示时钟数据
 * @param  None
 * @retval None
 */
static void Display(void)
{
    static Mode_TypeDef System_Old_Mode = Mode_Clock;
    if (System_Old_Mode != System_Mode)
    {
        lcd_clear();
        System_Old_Mode = System_Mode;
    }

    switch (System_Mode)
    {
    case Mode_Clock:
        Display_Clock(1, 2);
        break;

    case Mode_menu:
        Display_menu();
        break;

    case Mode_Stopwatch:
        Display_Stopwatch();
        break;

    case Mode_Timing:
        Display_Clock(1, 2);
        Display_Timing();
        break;

    case Mode_hour_report:
        Display_Clock(1, 2);
        Buzzer_Hour_report();
        break;
    }
}

/**
 * @brief  定时器1中断服务函数，
 *         定时器1用于刷新LCD
 * @param  None
 * @retval None
 */
void timer1_ini(void) interrupt 3
{
    TH1 = TIMER1_TH1;
    TL1 = TIMER1_TL0;

    Display();
}
